//日志器模块

#ifndef __M_LOGGER_H__
#define __M_LOGGER_H__
#include "util.hpp"
#include "level.hpp"
#include "format.hpp"
#include "sink.hpp"
#include "looper.hpp"
#include <atomic>
#include <vector>
#include <mutex>
#include <string>
#include <stdlib.h>
#include <cstdarg>
#include <unordered_map>

namespace mylog{
  class logger{
   public:
     using ptr = std::shared_ptr<logger>;
     logger(const std::string &logger_name,
            LogLevel::value level,
            Formatter::ptr &formatter,
            std::vector<LogSink::ptr> &sinks):
         _logger_name(logger_name),
         _limit_level(level),
         _formatter(formatter),
         _sink(sinks)
    {}
     //获取日志器名称，返回const修饰，防止被修改
     const std::string &name() {return _logger_name;}
     void debug(const std::string &file, size_t line, const std::string &fmt, ...)
     {
       //通过传入传入的参数构造出一个日志消息对象，进行日志的格式化，最终落地
       //1.判断当前的日志是否达到了输出等级
       if (LogLevel::value::DEBUG < _limit_level)  {return;}
       //2.对fmt格式化字符和不定参进行字符串组织，得到日志信息的字符串
       va_list ap;
       va_start(ap,fmt);
       char* res;
       int ret = vasprintf(&res, fmt.c_str(), ap);
       if(ret == -1){
         std::cout << "vasprintf failed!\n";
         return;
       }
       va_end(ap);
       Serialize(LogLevel::value::DEBUG, file, line, res);
       free(res);
     }
     void info(const std::string &file, size_t line, const std::string &fmt, ...)
     {
       if(LogLevel::value::INFO < _limit_level)  {return ;}
       va_list ap;
       va_start(ap, fmt);
       char* res;
       int ret = vasprintf(&res, fmt.c_str(),ap);
       if(ret == -1){
         std::cout << "vasprintf failed!\n";
         return;
       }
       va_end(ap);
       Serialize(LogLevel::value::INFO, file, line, res);
       free(res);
     } 
     void warn(const std::string &file, size_t line, const std::string &fmt, ...)
     {
       if(LogLevel::value::WARN < _limit_level)  {return ;}
       va_list ap;
       va_start(ap, fmt);
       char *res;
       int ret = vasprintf(&res, fmt.c_str(), ap);
       if(ret == -1){
         std::cout << "vasprintf failed!\n";
         return;
       }
       va_end(ap);
       Serialize(LogLevel::value::WARN, file, line, res);
       free(res);
     }
     void error(const std::string &file, size_t line, const std::string &fmt, ...)
     {

       if(LogLevel::value::ERROR < _limit_level)  {return ;}
       va_list ap;
       va_start(ap, fmt);
       char *res;
       int ret = vasprintf(&res, fmt.c_str(), ap);
       if(ret == -1){
         std::cout << "vasprintf failed!\n";
         return;
       }
       va_end(ap);
       Serialize(LogLevel::value::ERROR, file, line, res);
       free(res);
     }
     void fatal(const std::string &file, size_t line, const std::string &fmt, ...)
     {
       if(LogLevel::value::FATAL < _limit_level)  {return ;}
       va_list ap;
       va_start(ap, fmt);
       char *res;
       int ret = vasprintf(&res, fmt.c_str(), ap);
       if(ret == -1){
         std::cout << "vasprintf failed!\n";
         return;
       }
       va_end(ap);
       Serialize(LogLevel::value::FATAL, file, line, res);
       free(res);
     }
   protected:
     virtual void log(const char *data, size_t len) = 0;
     void Serialize(LogLevel::value level, const std::string &file, size_t line, char *str){
       //3.构造LogMsg对象
       LogMsg msg(line, level, file, _logger_name, str);
       //4.通过格式化工具对LogMsg进行格式化，得到格式化后的日志字符串
       std::stringstream ss;
       _formatter->format(ss,msg);
       //5.进行日志落地
       log(ss.str().c_str(), ss.str().size());
     }
   protected:
     std::mutex _mutex;  // 互斥锁，用于线程安全，确保多线程环境下日志记录的安全性
     std::string _logger_name; // 日志记录器的名称，用于在日志中标识记录器
     std::atomic<LogLevel::value> _limit_level; // 原子变量，表示日志的最小记录级别，只有高于或等于这个级别的日志才会被记录
     Formatter::ptr _formatter; // 格式化器指针，用于处理日志的格式化，将原始日志信息按照指定的格式进行输出
     std::vector<LogSink::ptr> _sink;// 日志记录的存储位置集合，可以是多个存储位置，例如同时记录到文件和控制台
  };

  class SyncLogger : public logger{ 
    public: 
    SyncLogger(const std::string &logger_name,
            LogLevel::value level,
            Formatter::ptr &formatter,
            std::vector<LogSink::ptr> &sinks):
         logger(logger_name, level, formatter, sinks){}
    protected:
      //同步日志器，是将日志直接通过落地模块句柄进行日志落地
      void log(const char *data, size_t len){
          std::unique_lock<std::mutex> lock(_mutex);
          for(auto &sink:_sink){
             sink->log(data, len);
          }
      }
  };
  
  class AsyncLogger : public logger{ 
    public: 
    AsyncLogger(const std::string &logger_name,
            LogLevel::value level,
            Formatter::ptr &formatter,
            std::vector<LogSink::ptr> &sinks,
            mylog::AsyncType looper_type):
         logger(logger_name, level, formatter, sinks),
         _looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::realLog, this, std::placeholders::_1), looper_type)){}
    protected:
      //将数据写入缓冲区当中
      void log(const char *data, size_t len){
         _looper ->push(data, len);
      }
      //设计一个实际落地函数(将缓冲区中的数据落地)
      void realLog(Buffer &buf){
         if(_sink.empty())  return;
         for (auto &sink : _sink){
            sink->log(buf.begin(), buf.readAbleSize());
         }
      }
    private:
      AsyncLooper::ptr _looper;
  };
  enum class LoggerType{
    Sync_logger = 0,
    Async_logger
  };
  //工厂模式
  class LoggerBuilder{
    public:
      LoggerBuilder(): _looper_type(AsyncType::ASYNC_SAFE),
                       _logger_type(LoggerType::Sync_logger),
                       _limit_level(LogLevel::value::DEBUG)
     {}
      void BuildLoggerType(LoggerType type) {_logger_type = type;}
      void BuildLoggerName(const std::string &name) {_logger_name = name;}
      void BuildLooperNotSafe()  {_looper_type = AsyncType::ASYNC_UNSAFE;}
      void BuildLoggerLevel(LogLevel::value level){_limit_level = level;}
      void BuildFormatter(const std::string pattern){
        _formatter = std::make_shared<Formatter>(pattern);
      }
      template<typename SinkType,typename ...Args>
        void BuildSink(Args &&...args){
          auto psink = SinkFactory::create<SinkType> (std::forward<Args>(args)...);
          _sink.push_back(psink);
        }
      virtual logger::ptr build() = 0;
    protected:
      mylog::AsyncType _looper_type;  //异步日志器类型
      LoggerType _logger_type; 
      std::string _logger_name; // 日志记录器的名称，用于在日志中标识记录器
      LogLevel::value _limit_level; // 原子变量，表示日志的最小记录级别，只有高于或等于这个级别的日志才会被记录
      Formatter::ptr _formatter; // 格式化器指针，用于处理日志的格式化，将原始日志信息按照指定的格式进行输出
      std::vector<LogSink::ptr> _sink;// 日志记录的存储位置集合，可以是多个存储位置，例如同时记录到文件和控制台
  };

  class LocalLoggerBuilder : public LoggerBuilder{
     public:
         logger::ptr build() override{
            assert(_logger_name.empty() == false);  //必须有日志器名称
            if(_formatter.get() == nullptr){
                _formatter = std::make_shared<Formatter>();
            }
            if(_sink.empty()){
               BuildSink<StdoutSink>();
             }
            if(_logger_type == LoggerType::Async_logger){
               return std::make_shared<AsyncLogger>(_logger_name, _limit_level, _formatter, _sink, _looper_type);
            }else{
               return std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sink);
            }
         }
  };
  class LoggerManager{
    public:
      static LoggerManager& GetInstance(){
        //C++11后，针对静态局部变量，编译器在编译层面实现了线程安全
        static LoggerManager eton;
        return eton;
      }
      void addLogger(logger::ptr &logger){
        if (hasLogger(logger->name()))  return; //假如已经存在,
        std::unique_lock<std::mutex> lock(_mutex); 
        _loggers.insert(std::make_pair(logger->name(), logger));
      }
      bool hasLogger(const std::string &name){ 
        std::unique_lock<std::mutex> lock(_mutex); 
        auto it = _loggers.find(name);
        if(it == _loggers.end()){
          return false;
        }
        return true;
      }
      logger::ptr getLogger(const std::string &name){
        std::unique_lock<std::mutex> lock(_mutex); 
        auto it = _loggers.find(name);
        if(it == _loggers.end()){
          return logger::ptr();
        }
        return it->second;
      }
      logger::ptr rootLogger(){
        return _root_logger;
      }

    private:
      LoggerManager() {     
         std::unique_ptr<mylog::LoggerBuilder> builder(new mylog::LocalLoggerBuilder());
         builder->BuildLoggerName("root");
         _root_logger = builder->build();
         _loggers.insert(std::make_pair("root", _root_logger));
      }
    private:
       std::mutex _mutex;
       logger::ptr _root_logger;  //默认日志器
       std::unordered_map<std::string, logger::ptr> _loggers;  //管理数组器
  };
  class GlobalLoggerBuilder : public LoggerBuilder{
     public:
         logger::ptr build() override{
            assert(_logger_name.empty() == false);  //必须有日志器名称
            if(_formatter.get() == nullptr){
                _formatter = std::make_shared<Formatter>();
            }
            if(_sink.empty()){
               BuildSink<StdoutSink>();
            }
            logger::ptr logger;
            if(_logger_type == LoggerType::Async_logger){
               logger = std::make_shared<AsyncLogger>(_logger_name, _limit_level, _formatter, _sink, _looper_type);
            }else{
               logger = std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sink);
            }
            LoggerManager::GetInstance().addLogger(logger);
            return logger;
       }
  };  
}
#endif
